<?php

class FormDataGateway //implements IRepository
{

  /**
   *
   * @var string
   */
  public $table;

  /**
   *
   * @var string
   */
  public $pk;

  /**
   *
   * @var array
   */
  public $behaviors = array();

  /**
   *
   * @var mixed
   */
  public $filter;

  /**
   *
   * @var array
   */
  protected static $instances = array();

  /**
   * Constructor.
   *
   * return void
   */
  public function __construct($table = null, $pk = null)
  {
    $this->table = $table;
    $this->pk = $pk;
  }

  /**
   *
   * @param string $table
   * @param string $pk
   * @return TableDataGateway
   */
  public static function getInstance($table, $pk = null)
  {
    if (! isset(self::$instances[$table])) {
      self::$instances[$table] = new self($table, $pk);
    }

    return self::$instances[$table];
  }

  /**
   *
   * @param int $offset
   * @param int $limit
   * @return Pager
   */
  public function findPager($params = null)
  {
    $limit = $params['limit'];
    $offset = $params['offset'];

    return new Pager($this->findCount($params), $limit, $offset);
  }

  /**
   *
   * @return array
   */
  public function find($id = null, $params = null)
  {
    $query = DB::getInstance()->query()->setParams($params)->from($this->table)->where($this->filter())->where("$this->pk = :$this->pk")->limit(1);

    $data = (array) sy_get_param($params, 'data');
    $data[$this->pk] = $id;

    $result = $query->execute($data)->fetchRow();

    return $result;
  }

  /**
   *
   * @return integer
   */
  public function findCount($params = null)
  {
    $query = DB::getInstance()->query()->setParams($params)->where($this->filter())->from($this->table)->select(false)->limit(false)->offset(false)->select("COUNT($this->pk)");
    $result = $query->execute(sy_get_param($params, 'data'))->fetchOne();
    return intval($result);
  }

  /**
   *
   * @param int $offset
   * @param int $limit
   * @return array
   */
  public function findAll($params = null)
  {
    $this->executeCallback('beforeFindAll', array(&$params));

    $query = DB::getInstance()->query()->setParams($params)->where($this->filter())->from($this->table);

    $result = $query->execute(sy_get_param($params, 'data'))->fetchAll();

    return $result;
  }

  /**
   *
   * @return integer
   */
  public function delete($id, $params = array())
  {
    $this->executeCallback('beforeDelete', array($id, $params));

    $result = DB::getInstance()->delete($this->table, "$this->pk = ?")->execute($id);

    $this->executeCallback('afterDelete', array($id, $params));

    return $result->numRows();
  }

  /**
   *
   * @return integer
   */
  public function deleteAll($params = null)
  {
    $result = DB::getInstance()->delete($this->table)->setParams($params)->execute();

    return $result->numRows();
  }

  /**
   *
   * @param array $data
   * @return mixed
   */
  public function save(&$data)
  {
    $id = sy_get_param($data, $this->pk);

    if (empty($id)) {
      return $this->insert($data);
    }
    else {
      return $this->update($data);
    }
  }

  /**
   *
   * @param array $data
   * @return void
   */
  public function insert(&$data)
  {
    $this->executeCallback('beforeInsert', array(&$data));

    DB::getInstance()->insert($this->table, $data)->execute($data);

    $data[$this->pk] = DB::getInstance()->lastInsertId();

    $this->executeCallback('afterInsert', array(&$data));
  }

  /**
   *
   * @param mixed $data
   * @return int
   */
  public function update(&$data)
  {
    $this->executeCallback('beforeUpdate', array(&$data));

    $result = 0;

    if (count($data) > 1) {
      $result = DB::getInstance()->update($this->table, $data, "$this->pk = :$this->pk")->execute($data)->numRows();
    }

    $this->executeCallback('afterUpdate', array(&$data));

    return $result;
  }

  protected function executeCallback($callback, $args = null)
  {
    foreach ($this->behaviors as $behavior) {
      if (method_exists($behavior, $callback)) {
        call_user_func_array(array($behavior, $callback), $args);
      }
    }
  }

  protected function filter()
  {
    if (! empty($this->filter)) {
      return $this->filter;
    }
    else {
      return " TRUE ";
    }
  }

}

?>